#include "pdfloader.h"
#include <QThread>
#include <QDebug>
#include <QPixmap>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "globaldef.h"
#include "poppler-qt5.h"
#include "logger.h"

class PdfLoaderPrivate : public QThread
{
    Q_OBJECT
signals:
    void load(const QPixmap &image);
    void done(const PdfLoader::PdfError &info);

private slots:
    void render(const QPixmap &image);

protected:
    void run();
    void clear();

private:
    QString m_fileName;
    quint64 m_maxMemory;
    QWidget *m_widget;
    PdfLoader::PdfDirection m_direction;
    friend class PdfLoader;
};

PdfLoader::PdfLoader(QWidget *parent, PdfDirection direction, quint64 maxMemory) : QObject(parent)
{
    d = new PdfLoaderPrivate;
    d->m_widget = parent;
    d->m_maxMemory = maxMemory;
    d->m_direction = direction;

    qRegisterMetaType<PdfLoader::PdfError>();
    connect(d, &PdfLoaderPrivate::done, this, &PdfLoader::done);
    connect(d, &PdfLoaderPrivate::load, d, &PdfLoaderPrivate::render);
}

PdfLoader::~PdfLoader()
{
    d->requestInterruption();
    d->quit();
    d->wait();
    d->deleteLater();
}

bool PdfLoader::load(const QString &fileName)
{
    if (!d->isRunning())
    {
        d->clear();
        d->m_fileName = fileName;
        d->start();
        return true;
    }

    sysError("render is running");
    return false;
}

void PdfLoaderPrivate::clear()
{
    QList<QLabel *> items = m_widget->findChildren<QLabel *>();
    for (int i = 0; i < items.count(); i++)
    {// 删除子控件
        items[i]->setParent(Q_NULLPTR);
        items[i]->deleteLater();
    }

    // 删除布局
    delete m_widget->layout();

    // 新建布局
    if (PdfLoader::Horizontal == m_direction)
    {
        m_widget->setLayout(new QHBoxLayout);
    }
    else
    {
        m_widget->setLayout(new QVBoxLayout);
    }
}

void PdfLoaderPrivate::render(const QPixmap &image)
{
    QLabel *label = new QLabel;
    label->setPixmap(image);
    m_widget->layout()->addWidget(label);
}

void PdfLoaderPrivate::run()
{
    sysDebug("%s render start.", m_fileName.toStdString().data());

    QScopedPointer<Poppler::Document> document(Poppler::Document::load(m_fileName));

    if (!document)
    {// 文件加载失败
        sysDebug("%s file load fail.", m_fileName.toStdString().data());
        emit done(PdfLoader::FileLoadError);
        return;
    }

    if (document->isLocked())
    {// 文件被锁定
        sysDebug("%s file is locked.", m_fileName.toStdString().data());
        emit done(PdfLoader::FileLockedError);
        return;
    }

    int total = document->numPages();

    for (int pageNumber = 0; pageNumber < total; pageNumber++)
    {// 渲染每一页
        QScopedPointer<Poppler::Page> pdfPage(document->page(pageNumber));
        if (!pdfPage)
        {// 页面加载失败
            sysDebug("%s page load fail.", m_fileName.toStdString().data());
            emit done(PdfLoader::PageLoadError);
            return;
        }

        QImage image = pdfPage->renderToImage(windowWidth >= 1280 ? 200 : 93.2, windowWidth >= 1280 ? 200 : 93.2);
        if (image.isNull())
        {// 页面内容转换为 QImage 失败
            sysDebug("%s page {%d} render fail.", m_fileName.toStdString().data(), pageNumber);
            emit done(PdfLoader::PageRenderError);
            return;
        }

        QImage renderImage = image.scaled(1024, 800, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
        emit load(QPixmap::fromImage(renderImage));

        if ((quint64)(renderImage.byteCount() * pageNumber) > m_maxMemory * 1048576)
        {
            sysDebug("%s too large, page render interrupted (load %1)", m_fileName.toStdString().data(), pageNumber);
            emit done(PdfLoader::OutOfMemory);
            return;
        }

        if (isInterruptionRequested())
        {
            sysDebug("%s render stopped.", m_fileName.toStdString().data());
            emit done(PdfLoader::stopped);
            return;
        }
    }

    emit done(PdfLoader::NoError);
    sysDebug("%s render done.", m_fileName.toStdString().data());
}


#include "pdfloader.moc"
